/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jili.ubert.clientapi;

import com.jili.ubert.clientapi.until.UnWorkException;
import com.jili.ubert.clientapi.until.AnswerHandler;
import com.jili.ubert.clientapi.until.AnswerMsgResult;
import com.jili.ubert.clientapi.until.AbstractWorker;
import com.jili.ubert.clientapi.listener.LastPriceListener;
import com.jili.ubert.clientapi.listener.PriceListener;
import com.jili.ubert.clientapi.provider.MarketDataProvider;
import com.jili.ubert.code.CodeTool;
import com.jili.ubert.code.client2server.Login;
import com.jili.ubert.code.client2server.RegistPriceMsg;
import com.jili.ubert.code.client2server.RequestPageData;
import com.jili.ubert.code.server2client.MsgResult;
import com.panemu.tiwulfx.common.TableData;
import com.jili.ubert.code.server2client.PageDataProto;
import com.jili.ubert.code.server2client.Price;
import com.jili.ubert.dao.OnDBDataAccpet;
import com.jili.ubert.dao.db.ObjInfo;
import com.jili.ubert.dao.db.ObjNewStock;
import com.jili.ubert.dao.db.ObjPriceTick;
import com.jili.ubert.dao.recent.RecentTradeNewOrder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author ChengJili
 */
class MarketDataClient implements MarketDataProvider{
    //1.成员变量

    private final MarketDataNettyClient client;
    private MarketDataRequest request;
    private DataPool dataPool;
    private static final Log log = LogFactory.getLog(MarketDataClient.class);
    private final HashMap<PriceListener, HashSet<String>> hanglersPrice = new HashMap<>();
    private final HashMap<LastPriceListener, HashSet<String>> hanglersLastPrice = new HashMap<>();
    private final HashMap<Integer, OnDBDataAccpet> dbdataacceptor = new HashMap<>();
//    private HashSet<PriceListener> hanglersPrice;
    private final SessionBucket sessionBucket = new SessionBucket();
    private final ListenPriceBucket listenPriceBucket = new ListenPriceBucket(128);
    //2.构造函数
    private AtomicInteger requstid = new AtomicInteger(0);

    private int getRequstID() {
        if (requstid.getAndIncrement() == Integer.MAX_VALUE) {
            requstid.getAndSet(Integer.MIN_VALUE);
        }
        return requstid.intValue();
    }

    public MarketDataClient() {
        this.client = new MarketDataNettyClient();
    }

    public MarketDataClient(String host, int port) {
        this.client = new MarketDataNettyClient();
        MsgResult ret = client.Connect(host, port, false, false, this);
        if (!ret.getSuccess()) {
            throw new UnWorkException(ret.getWord());
        }
    }

//    @Override
    public MsgResult Connect(String host, int port, boolean isSSL, boolean isZlib) {
        return client.Connect(host, port, isSSL, isZlib, this);
    }

//    @Override
    public int Login(Login login, AnswerHandler<MsgResult> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AnswerMsgResult();
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(1, id, login.EnCode(login));
        return id;
    }

//    @Override
    public int UserLogin(Login login, AnswerHandler<MsgResult> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AnswerMsgResult();
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(1, id, login.EnCode(login));
        return id;
    }

    @Override
    public int getLNCPrice(String objID, AnswerHandler<Double> handler) throws IOException {
        int id = this.getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                double data = CodeTool.BitToDouble(msg.getData());
                getAnswerHandler().OnAnswer(data);
            }
        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(1, id, CodeTool.StringToBit(objID));
        return id;
    }

    @Override
    public int getLastPrice(String objID, AnswerHandler<Double> handler) throws IOException {
        int id = this.getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                double data = CodeTool.BitToDouble(msg.getData());
                getAnswerHandler().OnAnswer(data);
            }
        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(2, id, CodeTool.StringToBit(objID));
        return id;
    }

    @Override
    public int getLastPriceQueue1(String objID, AnswerHandler<Price> handler) throws IOException {
        int id = this.getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                try {
                    Price data;
                    data = Price.DeCode(msg.getData());
                    getAnswerHandler().OnAnswer(data);
                } catch (IOException ex) {
                    Logger.getLogger(MarketDataClient.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(3, id, CodeTool.StringToBit(objID));
        return id;
    }

    @Override
    public int getLastPriceQueue5(String objID, AnswerHandler<Price> handler) throws IOException {
        int id = this.getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                try {
                    Price data;
                    data = Price.DeCode(msg.getData());
                    getAnswerHandler().OnAnswer(data);
                } catch (IOException ex) {
                    Logger.getLogger(MarketDataClient.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(4, id, CodeTool.StringToBit(objID));
        return id;
    }

    @Override
    public int getLastPriceQueue10(String objID, AnswerHandler<Price> handler) throws IOException {
        int id = this.getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                try {
                    Price data;
                    data = Price.DeCode(msg.getData());
                    getAnswerHandler().OnAnswer(data);
                } catch (IOException ex) {
                    Logger.getLogger(MarketDataClient.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        client.SendSYNCMsg(5, id, CodeTool.StringToBit(objID));
        return id;
    }
/*
    @Override
    public int RegistPrice(List<String> objList, int type , AnswerHandler<Price> handler) throws IOException {
        int id = this.getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                try {
                    MsgResult data;
                    data = MsgResult.DeCode(msg.getData());
                    if (data.isSuccess()) {
                        getAnswer().IsSuccess();
                    } else {
                        getAnswer().OnAnswer(data);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(MarketDataClient.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        objList.stream().forEach((objid)->{this.listenPriceBucket.Register(objid, handler);});
        
        RequestPageData rqt = new RequestPageData();
        rqt.setKeylist(objList);
        rqt.setWantPage(type);
        client.SendSYNCMsg(7, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int RegistPrice(List<String> objList, AnswerHandler<Price> handler) throws IOException {
        return RegistPrice(objList, 0, handler);
    }

    @Override
    public int QueryObjList(AnswerHandler<TableData<ObjInfo>> handler) throws IOException{
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjInfo> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjInfo> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjInfo.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int RegistPrice(String mk, String obj, int type, AnswerHandler<Price> handler) throws IOException {
        List<String> objlist = new ArrayList<>();
        objlist.add(mk+obj);
        return RegistPrice(objlist,0,handler);
    }

    @Override
    public int RegistPrice(String mk, String obj, AnswerHandler<Price> handler) throws IOException {
        return RegistPrice(mk,obj,0,handler);
    }

    @Override
    public int RemoveRegistPrice(List<String> objList, AnswerHandler<MsgResult> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AnswerMsgResult();
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        objList.stream().forEach((objid)->{this.listenPriceBucket.CancelRegister(objid);});
        
        RequestPageData rqt = new RequestPageData();
        rqt.setKeylist(objList);
        client.SendSYNCMsg(7, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int RemoveRegistPrice(String mk, String obj, AnswerHandler<MsgResult> handler) throws IOException {
        List<String> objlist = new ArrayList<>();
        objlist.add(mk+obj);
        return RemoveRegistPrice(objlist,handler);
    }

    @Override
    public int QueryObjList(String obj, AnswerHandler<TableData<ObjInfo>> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjInfo> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjInfo> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjInfo.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        List<String> keylist = new ArrayList<>();
        keylist.add(obj);
        rqt.setKeylist(keylist);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int QueryObjList(String mk, String obj, AnswerHandler<ObjInfo> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjInfo> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjInfo> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjInfo.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        List<String> keylist = new ArrayList<>();
        keylist.add(mk+obj);
        rqt.setKeylist(keylist);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int QueryNewObjList(AnswerHandler<TableData<ObjNewStock>> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjNewStock> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjNewStock> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjNewStock.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        List<String> keylist = new ArrayList<>();
        keylist.add("all");
        rqt.setKeylist(keylist);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int QueryPriceTickList(AnswerHandler<TableData<ObjPriceTick>> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjPriceTick> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjPriceTick> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjPriceTick.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        List<String> keylist = new ArrayList<>();
        keylist.add("all");
        rqt.setKeylist(keylist);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int QueryPriceTick(String obj, AnswerHandler<TableData<ObjPriceTick>> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjPriceTick> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjPriceTick> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjPriceTick.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        List<String> keylist = new ArrayList<>();
        keylist.add(obj);
        rqt.setKeylist(keylist);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }

    @Override
    public int QueryPriceTick(String mk, String obj, AnswerHandler<ObjPriceTick> handler) throws IOException {
        int id = getRequstID();
        AbstractWorker worker = new AbstractWorker() {

            @Override
            public void Onhandler(MsgEntity msg) {
                PageDataProto data;
                try {
                    data = PageDataProto.DeCode(msg.getData());
                    TableData<ObjPriceTick> data0 = new TableData<>();
                    data0.setCurrentPage(data.getCurrentPage());
                    data0.setMaxNum(data.getMaxNum());
                    data0.setTotalNum(data.getTotalNum());
                    List<ObjPriceTick> poss = new ArrayList<>();
                    data.getDataList().stream().forEach((byte[] posb) -> {
                        try {
                            poss.add(ObjPriceTick.DeCode(posb));
                        } catch (IOException ex) {
                            log.info("QueryObjList-getDataList fail decode:" + ex);
                        }
                    });
                    data0.setDataList(poss);
                    getAnswer().OnAnswer(data0);
                } catch (IOException ex) {
                    log.info("QueryObjList fail decode:" + ex);
                }
            }

        };
        worker.setAnswerHandler(handler);
        this.sessionBucket.AcceptSession(id, worker);
        RequestPageData rqt = new RequestPageData();
        rqt.setWantPage(1);
        rqt.setMaxNum(500);
        rqt.setSortDirect(true);
        List<String> keylist = new ArrayList<>();
        keylist.add(mk+obj);
        rqt.setKeylist(keylist);
        client.SendSYNCMsg(22, id, RequestPageData.EnCode(rqt));
        return id;
    }
*/
    public void AccpetSessionAnswer(int id,MsgEntity msg) {
        this.sessionBucket.OnDealSession(id,msg);
    }

    @Override
    public void RemoveRegistPrice(String objid, AnswerHandler<Price> handler) throws IOException {
        this.listenPriceBucket.CancelRegister(objid, handler);
    }

    @Override
    public int RegistPrice(List<String> objList, int type, AnswerHandler<Price> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int RegistPrice(String mk, String obj, int type, AnswerHandler<Price> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int RegistPrice(List<String> objList, AnswerHandler<Price> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int RegistPrice(String mk, String obj, AnswerHandler<Price> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int RemoveRegistPrice(List<String> objList, AnswerHandler<MsgResult> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int RemoveRegistPrice(String mk, String obj, AnswerHandler<MsgResult> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryObjList(AnswerHandler<TableData<ObjInfo>> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryObjList(String obj, AnswerHandler<TableData<ObjInfo>> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryObjList(String mk, String obj, AnswerHandler<ObjInfo> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryNewObjList(AnswerHandler<TableData<ObjNewStock>> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryPriceTickList(AnswerHandler<TableData<ObjPriceTick>> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryPriceTick(String obj, AnswerHandler<TableData<ObjPriceTick>> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int QueryPriceTick(String mk, String obj, AnswerHandler<ObjPriceTick> handler) throws IOException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    public void setRequest(MarketDataRequest marketDataRequest) {
        this.request = marketDataRequest;
    }

    public void setDataPool(DataPool dataPool) {
        this.dataPool = dataPool;
    }

}
